#pragma once
#ifndef Sdk_STRING_HH
#define Sdk_STRING_HH

#include <vector>
#include <sstream>
#include <string>
#include <OgreStringConverter.h>
#include "LitPrerequisites.h"

namespace Lit
{
	class LIT_API Tokenizer
	{
		std::string mStr;
	public:
		Tokenizer( );
		Tokenizer( const std::string &str );
		Tokenizer( const Tokenizer& rk );
		~Tokenizer();

		std::string arg( size_t id ) const;
		bool isValid( size_t requ_min_args = 0 ) const;
		std::string str() const;
		template<typename T> 
		T takeNext()
		{
			if( mStr.empty() ) throw std::range_error( "no more argument to extract" );
			std::stringstream ss(mStr);
			T t;
			ss >> t;
			mStr = ss.str();
			return t;
		}
		Tokenizer eat( size_t num );
		bool hasNext() const;
	};
	class LIT_API String;
	LIT_API std::ostream& operator<<( std::ostream& strm, const String &str );

	class LIT_API String 
	{
		std::string d;
	public:
		friend LIT_API std::ostream& operator<<( std::ostream& strm, const String &str );

		typedef std::string::iterator iterator;
		typedef std::string::const_iterator const_iterator;

		template<typename T> String( const T &var ){ std::stringstream ss; ss << var; d = ss.str(); }
		template<> String( const std::string &str ) : d( str ){ }
		String( const String &rk );
		String( const char * str );
		String( );

		template<typename T>
		String arg( const T& a ) const
		{
			size_t p = d.find_first_of( "%%" );
			if( p == std::string::npos ) return *this;
			
			String ret(d);
			ret.d.erase( p, 2 );
			ret.d.insert( p, String(a).cstr() );

			return *this;
		}
		bool endsWith( const Lit::String &str ) const;
		void trim( );
		char &at( size_t i );
		char& operator[]( size_t i );
		char at( size_t i ) const;
		
		std::string* operator->();
		const std::string* operator->() const;

		std::string& operator*();
		const std::string& operator*() const;
		
		size_t replaceBy( const String& what, const String &to ) ;
		std::vector<Lit::String> tokenise( const std::string &delims = " ", const std::string &double_delims = "\"" ) const;
		void replaceAll( const std::string &what, const std::string &byWhat );
		void replace( iterator it, const String & str );
		void erase( iterator it );
		bool empty() const;
		size_t length() const;
		size_t size() const;
		size_t count() const;
		size_t capacity() const;
		size_t find( char c ) const;
		String substr( size_t pos, size_t count ) const;
		
		template<typename T> T to() const{ std::stringstream ss(d); T out; ss >> out; return out; }
		template<> std::string to() const{ return d; }
		template<> Lit::String to() const{ return d; }
		template<> const char* to() const{ return d.c_str(); }


		iterator find( char c );
		iterator begin();
		iterator end();
		const_iterator begin() const;
		const_iterator end() const;
		
		bool operator<( Lit::String rk );
		bool operator>( Lit::String rk );
		bool operator==( const Lit::String &rk ) const;
		bool operator==( const std::string &rk ) const;
		bool operator==( const char * str ) const;

		template<typename T> String& operator += ( const T &var ){ std::stringstream ss; ss << var; d += ss.str(); return *this;} 
		template<> String& operator += ( const std::string &rk ){ d += rk;  return *this;}
		String& operator += ( const char* rk );
		String& operator += ( const String &rk );

		template<typename T> String operator + ( const T &var ) const{ std::stringstream ss; ss << var; return String(d + ss.str()); } 
		template<> String operator + ( const std::string &rk ) const{  return String(d + rk); }
		String operator + ( const char* rk ) const;
		String operator + ( const String &rk ) const;

		template<typename T> String& operator = ( const T &var ){ std::stringstream ss; ss << var; d = ss.str(); return *this;} 
		template<> String& operator = ( const std::string &rk ){ d = rk;  return *this;}
		String& operator = ( const char* rk );
		String& operator = ( const String &rk );
		
		template<typename T> String& operator () (  const T &var ){ std::stringstream ss; ss << var; d += ss.str(); return *this;}
		template<> String& operator () ( const String &rk ){ d += rk.d;  return *this;}
		template<> String& operator () ( const std::string &rk ){ d += rk;  return *this;}
		String& operator () ( const char* rk );
		
		template<typename T> String& operator << (  const T &var );
		template<> String& operator << ( const String &rk );
		template<> String& operator << ( const std::string &rk );
		String& operator << ( const char* rk );

		std::vector<Lit::String> explode( const String &delimiter = " " ) const;

		std::string str() const;
		const char* cstr() const;
		
		operator std::string	(void) const;
		operator char const *	(void) const;
	};

	class LIT_API StringList
	{
	public:
		typedef std::vector<String> type;
		typedef type::iterator itor;
		typedef type::const_iterator const_itor;
	protected:
		type mStrings;
		size_t mDefault;
		std::string mDefaultStr;
	public:
		StringList(int default_ = 0);
		StringList(const std::string&);
		StringList( const StringList & rk );
		StringList( int def_, const StringList & rk );
		StringList( const std::string& def_, const StringList & rk );
		~StringList();

		bool empty() const;
		size_t count() const;
		
		String& at( size_t id );
		const String& at( size_t id ) const;
		bool has( const String &str ) const;

		size_t findId( const String & str ) const;
		
		itor find( const String &str );
		const_itor find( const String &str ) const;
		itor begin();
		itor end();
		const_itor begin() const;
		const_itor end() const;


		void clear();
		StringList& push( const String & str );
		String pop();
		
		void setDefault( const size_t default_ );
		void setDefaultString( const std::string& default_ );
		size_t defaultString() const;

		StringList& operator()( const String &str );
		StringList& operator<<( const String &str );
		
		static StringList fromString( const String& str, const String& delim = "<;;>" );
		String str( const String &delim = String("<;;>") ) const;

		String selected() const;
	};
};

LIT_API Lit::String operator + ( const char * str, const Lit::String &str2 );
LIT_API std::string operator + ( const std::string& str, const Lit::String &str2 );

#endif